/*
    functions useful for parsing GHCN data
    Copyright (C) 2009-2013 Bob Mottram
    bob@sluggish.dyndns.org

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "ghcn.h"

ghcn::ghcn() {
}

ghcn::~ghcn() {
}

bool ghcn::station_has_property(int property_type,string value,
								long long int station_number,
								vector<stationdata> &stations)
{
	for (int i = 0; i < (int)stations.size(); i++) {
		if (stations[i].number == station_number) {
			switch (property_type) {
			case PROPERTY_POPULATION_CLASS: {
				if (stations[i].population_class==value) {
					return true;
				}
				return false;
			}
			}
		}
	}
	return false;
}


bool ghcn::vector_contains(vector<int> &list, int num_to_find)
{
	vector<int>::iterator result;
    result = find( list.begin(), list.end(), num_to_find );
    if( result == list.end() )
    	return(false);
    else
    	return(true);
}

bool ghcn::vector_contains(vector<long long int> &list, long long int num_to_find)
{
	vector<long long int>::iterator result;
    result = find( list.begin(), list.end(), num_to_find );
    if( result == list.end() )
    	return(false);
    else
    	return(true);
}

bool ghcn::FileExists(string filename)
{
  ifstream file;
  file.open(filename.c_str());

  // Check if the file exists
  if (file.is_open() == true) {
    file.close();
    return true;
  }

  return(false);
}

void ghcn::get_country_codes(
	vector<string> &find_countries,
	vector<long long int> &code,
	vector<string> &country,
	vector<long long int> &result)
{
	result.clear();

	if (find_countries.size() == 1) {
		if (find_countries[0] == "africa") {
			find_countries.clear();
			find_countries.push_back("algeria");
			find_countries.push_back("angola");
			find_countries.push_back("benin");
			find_countries.push_back("botswana");
			find_countries.push_back("burkina Faso");
			find_countries.push_back("burundi");
			find_countries.push_back("cameroon");
			find_countries.push_back("cape Verde");
			find_countries.push_back("chad");
			find_countries.push_back("congo");
			find_countries.push_back("djibouti");
			find_countries.push_back("egypt");
			find_countries.push_back("equatorial guinea");
			find_countries.push_back("eritrea");
			find_countries.push_back("ethiopia");
			find_countries.push_back("gabon");
			find_countries.push_back("gambia");
			find_countries.push_back("ghana");
			find_countries.push_back("guinea bissau");
			find_countries.push_back("guinea");
			find_countries.push_back("ivory Coast");
			find_countries.push_back("kenya");
			find_countries.push_back("lesotho");
			find_countries.push_back("liberia");
			find_countries.push_back("libya");
			find_countries.push_back("madagascar");
			find_countries.push_back("malawi");
			find_countries.push_back("mali");
			find_countries.push_back("mauritania");
			find_countries.push_back("mauritius");
			find_countries.push_back("morocco");
			find_countries.push_back("mozambique");
			find_countries.push_back("namibia");
			find_countries.push_back("niger");
			find_countries.push_back("nigeria");
			find_countries.push_back("reunion");
			find_countries.push_back("rwanda");
			find_countries.push_back("senegal");
			find_countries.push_back("seychelles");
			find_countries.push_back("sierra Leone");
			find_countries.push_back("somalia");
			find_countries.push_back("south africa");
			find_countries.push_back("sudan");
			find_countries.push_back("swaziland");
			find_countries.push_back("tanzania");
			find_countries.push_back("togo");
			find_countries.push_back("tunisia");
			find_countries.push_back("uganda");
			find_countries.push_back("zambia");
			find_countries.push_back("zanzibar");
			find_countries.push_back("zimbabwe");
		}
		if (find_countries[0] == "russia") {
			find_countries.clear();
			find_countries.push_back("russian federation (asian sector)");
			find_countries.push_back("russian federation (european sector)");
		}
		if (find_countries[0] == "north america") {
			find_countries.clear();
			find_countries.push_back("canada");
			find_countries.push_back("united states");
			find_countries.push_back("mexico");
		}
		if (find_countries[0] == "central america") {
			find_countries.clear();
			find_countries.push_back("guatemala");
			find_countries.push_back("belize");
			find_countries.push_back("honduras");
			find_countries.push_back("el salvador");
			find_countries.push_back("nicaragua");
			find_countries.push_back("costa rica");
			find_countries.push_back("panama");
		}
		if (find_countries[0] == "south america") {
			find_countries.clear();
			find_countries.push_back("argentina");
			find_countries.push_back("bolivia");
			find_countries.push_back("brazil");
			find_countries.push_back("chile");
			find_countries.push_back("colombia");
			find_countries.push_back("ecuador");
			find_countries.push_back("guyana");
			find_countries.push_back("paraguay");
			find_countries.push_back("peru");
			find_countries.push_back("suriname");
			find_countries.push_back("uruguay");
			find_countries.push_back("venezuela");
		}
		if (find_countries[0] == "america") {
			find_countries.clear();
			find_countries.push_back("canada");
			find_countries.push_back("united states");
			find_countries.push_back("mexico");
			find_countries.push_back("guatemala");
			find_countries.push_back("belize");
			find_countries.push_back("honduras");
			find_countries.push_back("el salvador");
			find_countries.push_back("nicaragua");
			find_countries.push_back("costa rica");
			find_countries.push_back("panama");
			find_countries.push_back("argentina");
			find_countries.push_back("bolivia");
			find_countries.push_back("brazil");
			find_countries.push_back("chile");
			find_countries.push_back("colombia");
			find_countries.push_back("ecuador");
			find_countries.push_back("guyana");
			find_countries.push_back("paraguay");
			find_countries.push_back("peru");
			find_countries.push_back("suriname");
			find_countries.push_back("uruguay");
			find_countries.push_back("venezuela");
		}
		if (find_countries[0] == "west indies") {
			find_countries.clear();
			find_countries.push_back("the bahamas");
			find_countries.push_back("jamaica");
			find_countries.push_back("cuba");
			find_countries.push_back("cayman islands (u.k.)");
			find_countries.push_back("puerto rico (u.s.a.)");
			find_countries.push_back("british virgin islands (u.k.)");
			find_countries.push_back("antigua and barbuda");
			find_countries.push_back("saint kitts and nevis");
			find_countries.push_back("guadeloupe (france)");
			find_countries.push_back("dominica");
			find_countries.push_back("martinique (france)");
			find_countries.push_back("saint lucia");
			find_countries.push_back("saint vincent and the grenadines");
			find_countries.push_back("grenada");
			find_countries.push_back("barbados");
			find_countries.push_back("trinidad and tobago");
		}
		if ((find_countries[0] == "eu") ||
			(find_countries[0] == "europe")) {
			find_countries.clear();
			find_countries.push_back("austria");
			find_countries.push_back("belgium");
			find_countries.push_back("bulgaria");
			find_countries.push_back("cyprus");
			find_countries.push_back("czech republic");
			find_countries.push_back("denmark");
			find_countries.push_back("estonia");
			find_countries.push_back("finland");
			find_countries.push_back("france");
			find_countries.push_back("germany");
			find_countries.push_back("greece");
			find_countries.push_back("hungary");
			find_countries.push_back("republic of ireland");
			find_countries.push_back("italy");
			find_countries.push_back("latvia");
			find_countries.push_back("lithuania");
			find_countries.push_back("luxembourg");
			find_countries.push_back("malta");
			find_countries.push_back("netherlands");
			find_countries.push_back("poland");
			find_countries.push_back("portugal");
			find_countries.push_back("romania");
			find_countries.push_back("slovakia");
			find_countries.push_back("slovenia");
			find_countries.push_back("spain");
			find_countries.push_back("sweden");
			find_countries.push_back("united kingdom");
		}
		if (find_countries[0] == "g8") {
			find_countries.clear();
			find_countries.push_back("canada");
			find_countries.push_back("france");
			find_countries.push_back("germany");
			find_countries.push_back("italy");
			find_countries.push_back("japan");
			find_countries.push_back("russian federation (asian sector)");
			find_countries.push_back("russian federation (european sector)");
			find_countries.push_back("united kingdom");
			find_countries.push_back("united states");
		}
		if (find_countries[0] == "g20") {
			find_countries.clear();
			find_countries.push_back("argentina");
			find_countries.push_back("australia");
			find_countries.push_back("brazil");
			find_countries.push_back("canada");
			find_countries.push_back("china");
			find_countries.push_back("france");
			find_countries.push_back("germany");
			find_countries.push_back("india");
			find_countries.push_back("indonesia");
			find_countries.push_back("italy");
			find_countries.push_back("japan");
			find_countries.push_back("mexico");
			find_countries.push_back("russian federation (asian sector)");
			find_countries.push_back("russian federation (european sector)");
			find_countries.push_back("saudi arabia");
			find_countries.push_back("south africa");
			find_countries.push_back("south korea");
			find_countries.push_back("turkey");
			find_countries.push_back("united kingdom");
			find_countries.push_back("united states");
		}
	}

	for (int i = 0; i < (int)find_countries.size(); i++) {
		if (find_countries[i] == "uk") find_countries[i] = "united kingdom";
		if ((find_countries[i] == "us") || (find_countries[i] == "usa")) find_countries[i] = "united states";
		const char* str1 = find_countries[i].c_str();
		for (int j = 0; j < (int)country.size(); j++) {
			const char* str2 = country[j].c_str();

			// Got completely frustrated trying to use the string compare function
			// so just wrote my own character by character string comparison
			// surely better than this is possible
			int min = (int)country[j].size();
			if ((int)find_countries[i].size() < min) min = (int)find_countries[i].size();

			int k = 0;
			for (k = 0; k < min; k++) {
				if (str1[k] != str2[k]) {
					break;
				}
			}

			if (k == min) {
				result.push_back(code[j]);
			}
		}
	}

}

void ghcn::load_country_codes(
	string filename,
	vector<long long int> &code,
	vector<string> &country)
{
	if (FileExists(filename)) {
		ifstream iFile(filename.c_str());

		code.clear();
		country.clear();
		string str = "";
		while (!iFile.eof())
		{
			getline(iFile, str);
			if (str.size() > 0) {
				code.push_back((long long int)atoi(str.substr(0,3).c_str()));
				string str2 = str.substr(4, (int)(str.size())-4);
				//remove(str2.begin(),str2.end(),' ');
				const char* str3 = str2.c_str();
				string s = "";
				for (int i = 0; i < (int)str2.size(); i++) {
					if (str3[i] != '.') {
						char c = tolower(str3[i]);
						if (((c >= '0') && (c <= '9')) ||
							((c >= 'a') && (c <= 'z')) ||
							(c == ' ') ||
							(c == '(') ||
							(c == ')')) {
						    s += c;
						}
					}
					if (str3[i] == ')') break;
				}
				country.push_back(s);
				//printf("country %s\n",s.c_str());
			}
		}
		iFile.close();
	}
	else {
		printf("File not found\n%s\n", filename.c_str());
	}
}

void ghcn::save_stations(
	string kml_filename,
	vector<stationdata> &stations)
{
    ofstream kmlfile;
    kmlfile.open(kml_filename.c_str());
    kmlfile << "<?xml version=" << '"' << "1.0" << '"' << " encoding='UTF-8'?>\n";
    kmlfile << "<kml xmlns=" << '"' << "http://www.opengis.net/kml/2.2" << '"' << ">\n";
    kmlfile << "<Document>\n";
    for (int i = 0; i < (int)stations.size(); i++) {
		kmlfile << "  <Placemark>\n";
		kmlfile << "    <name>" << stations[i].name << "</name>\n";
		kmlfile << "    <description>Weather station number " << stations[i].number;
		if (stations[i].topography_class!="") {
			kmlfile << "\nPopulation class: " << stations[i].population_class;
			if (stations[i].population_size>0) {
				kmlfile << "\nPopulation size: " << stations[i].population_size;
			}
			kmlfile << "\nTopography class: " << stations[i].topography_class;
			kmlfile << "\nVegetation class: " << stations[i].vegetation_class;
			kmlfile << "\nWater class: " << stations[i].water_class;
			if (stations[i].water_distance_metres>0) {
				kmlfile << "\nWater distance (metres): " << stations[i].water_distance_metres;
			}
			kmlfile << "\nAirport class: " << stations[i].airport_class;
			if (stations[i].population_distance_metres>0) {
				kmlfile << "\nPopulation distance (metres): " << stations[i].population_distance_metres;
			}
			kmlfile << "\nGridded vegetation class: " << stations[i].gridded_vegetation_class;
			kmlfile << "\nSatellite population class: " << stations[i].satellite_population_class;
		}
		kmlfile << "</description>\n";
		kmlfile << "    <Point>\n";
		kmlfile << "      <coordinates>" << -stations[i].longitude << "," << stations[i].latitude << "," << stations[i].altitude << "</coordinates>\n";
		kmlfile << "    </Point>\n";
		kmlfile << "  </Placemark>\n";
    }
    kmlfile << "</Document>\n";
    kmlfile << "</kml>\n";
    kmlfile.close();
}

bool ghcn::get_station_location(long long int station,
								vector<stationdata> &stations,
								float &north,
								float &west,
								float &altitude)
{
	for (int i = 0; i < (int)stations.size(); i++) {
		if (stations[i].number==station) {
			north = stations[i].latitude;
			west = stations[i].longitude;
			altitude = stations[i].altitude;
			return true;
		}
	}
	return false;
}

bool ghcn::station_within_area(
							   long long int station_number,
							   vector<stationdata> &stations,
							   float latitudeN1,
							   float longitudeW1,
							   float latitudeN2,
							   float longitudeW2)
{
	float north=0,west=0,altitude=0;

	if (!get_station_location(station_number,
							  stations,
							  north,west,altitude)) {
		return false;
	}

	if (latitudeN2 < latitudeN1) {
		float temp = latitudeN1;
		latitudeN1 = latitudeN2;
		latitudeN2 = temp;
	}

	if ((longitudeW1 == 0.0f) &&
		(longitudeW2 == 0.0f)) {
		// station between two latitudes
		if ((north >= latitudeN1) &&
			(north <= latitudeN2)) {
			return true;
		}
	}
	else {
		// station within an area
		if (longitudeW2 < longitudeW1) {
			float temp = longitudeW1;
			longitudeW1 = longitudeW2;
			longitudeW2 = temp;
		}

		float w = longitudeW2 - longitudeW1;
		if (w > 180) w = 360 - w;
		if (w < -180) w = -360 + w;
		float h = latitudeN2 - latitudeN1;
		if (h > 180) h = 360 - h;
		if (h < -180) h = -360 + h;
		float cx = longitudeW1 + (w/2);
		float cy = latitudeN1 + (h/2);
		float r1 = w/2;
		float r2 = h/2;

		float dy = north - cy;
		if (dy > 180) dy = 360 - dy;
		if (dy < -180) dy = -360 + dy;
		if (fabs(dy) < r2) {
			float dx = west - cx;
			if (dx > 180) dy = 360 - dx;
			if (dx < -180) dy = -360 + dx;
			if (fabs(dx) < r1) {
				return true;
			}
		}
	}
	return false;
}

void ghcn::get_stations_within_area(
	float latitudeN1,
	float longitudeW1,
	float latitudeN2,
	float longitudeW2,
	vector<stationdata> &stations,
	vector<stationdata> &returned_station_numbers)
{
	if (latitudeN2 < latitudeN1) {
		float temp = latitudeN1;
		latitudeN1 = latitudeN2;
		latitudeN2 = temp;
	}

	if ((longitudeW1 == 0.0f) &&
		(longitudeW2 == 0.0f)) {
		// stations between two latitudes
	    for (int i = 0; i < (int)stations.size(); i++) {
	    	if ((stations[i].latitude >= latitudeN1) &&
	    		(stations[i].latitude <= latitudeN2)) {
	    		returned_station_numbers.push_back(stations[i]);
	    	}
	    }
	}
	else {
		// stations within an area
		if (longitudeW2 < longitudeW1) {
			float temp = longitudeW1;
			longitudeW1 = longitudeW2;
			longitudeW2 = temp;
		}

		float w = longitudeW2 - longitudeW1;
		if (w > 180) w = 360 - w;
		if (w < -180) w = -360 + w;
		float h = latitudeN2 - latitudeN1;
		if (h > 180) h = 360 - h;
		if (h < -180) h = -360 + h;
		float cx = longitudeW1 + (w/2);
		float cy = latitudeN1 + (h/2);
		float r1 = w/2;
		float r2 = h/2;

		for (int i = 0; i < (int)stations.size(); i++) {
			float dy = stations[i].latitude - cy;
			if (dy > 180) dy = 360 - dy;
			if (dy < -180) dy = -360 + dy;
			if (fabs(dy) < r2) {
				float dx = stations[i].longitude - cx;
				if (dx > 180) dy = 360 - dx;
				if (dx < -180) dy = -360 + dx;
				if (fabs(dx) < r1) {
					returned_station_numbers.push_back(stations[i]);
				}
			}
		}
	}
}

void ghcn::get_stations_from_data(vector<tempdata> &data,
								  vector<long long int> &stations,
								  float min_temp, float max_temp,
								  int start_month, int end_month,
								  vector<long long int> &country_codes)
{
	for (int i = 0; i < (int)data.size(); i++) {
		if ((data[i].temperature >= min_temp) &&
			(data[i].temperature <= max_temp)) {
			if (((end_month>=start_month) &&
				((data[i].month>=start_month) && (data[i].month<=end_month))) ||				
				((end_month<start_month) &&
				 ((data[i].month<=start_month) || (data[i].month>=end_month)))) {

				bool found = true;

				if (country_codes.size()>0) {
					found = false;
					for (int j = 0; j < (int)country_codes.size(); j++) {
						if (data[i].country_code==(int)country_codes[j]) {
							found = true;
							break;
						}
					}
				}

				if ((found) && (!vector_contains(stations,data[i].station))) {
					stations.push_back(data[i].station);
				}				
			}
		}
	}
}

bool ghcn::station_number_in_data(long long int station,
								  vector<long long int> &stations_list)
{
	for (int i = 0; i < (int)stations_list.size(); i++) {
		if (stations_list[i] == station) return true;
	}
	return false;
}

bool ghcn::station_exists(vector<stationdata> &stations,
						  long long int number)
{
	for (int i = 0; i < (int)stations.size(); i++) {
		if (stations[i].number == number) return true;
	}
	return false;
}

void ghcn::load_stations_v3(
	string filename,
	vector<stationdata> &stations,
	vector<tempdata> &data,
	vector<long long int> &country_codes,
	float min_temp, float max_temp,
	int start_month, int end_month,
	string population_class)
{
	// Get a list of weather stations which exist within the data
	vector<long long int> stations_list;
	get_stations_from_data(data,
						   stations_list,
						   min_temp, max_temp,
						   start_month, end_month,
						   country_codes);

	string str = "";
	ifstream iFile(filename.c_str());
	while (!iFile.eof()) {
		getline(iFile, str);

		if (str != "") {
			if (str.length()>=106) {
				long long int country_code = (long long int)atoi(str.substr(0,3).c_str());
				long long int station = (long long int)atof(str.substr(0,11).c_str());
				if ((stations_list.size()==0) ||
					(station_number_in_data(station,stations_list))) {
					string pop_class = str.substr(73,1);
					if ((population_class=="") ||
						((population_class!="") && (population_class==pop_class))) {
						float latitude = atof(str.substr(11,9).c_str());
						float longitude = -atof(str.substr(20,10).c_str());
						float altitude = atof(str.substr(30,7).c_str());
						int population_size = atoi(str.substr(74,5).c_str())*1000;
						string topography_class = str.substr(79,2);
						string vegetation_class = str.substr(81,2);
						string water_class = str.substr(83,2);
						int water_distance_metres = atoi(str.substr(85,2).c_str())*1000;
						string airport_class = str.substr(87,1);
						int population_distance_metres = atoi(str.substr(88,2).c_str())*1000;
						string gridded_vegetation_class = str.substr(90,16);
						string satellite_population_class = str.substr(106,1);
					
						const char * namestr = str.substr(38,30).c_str();
						string name="";
						for (int i=0;i<strlen(namestr);i++) {
							if (((namestr[i]>='A') && (namestr[i]<='Z')) ||
								((namestr[i]>='a') && (namestr[i]<='z')) ||
								(namestr[i]==' ') ||
								(namestr[i]=='-') ||
								(namestr[i]=='.')) {
								name += namestr[i];
							}
						}
					
						stationdata s;
						s.number = station;
						s.name = name;
						s.latitude = latitude;
						s.longitude = longitude;
						s.altitude = altitude;
						s.population_class = pop_class;
						s.population_size = population_size;
						s.topography_class = topography_class;
						s.vegetation_class = vegetation_class;
						s.water_class = water_class;
						s.water_distance_metres = water_distance_metres;
						s.airport_class = airport_class;
						s.population_distance_metres = population_distance_metres;
						s.gridded_vegetation_class = gridded_vegetation_class;
						s.satellite_population_class = satellite_population_class;					
						stations.push_back(s);
					}
				}
			}
		}
	}
	iFile.close();
}

void ghcn::load_stations_v2(
	string filename,
	vector<stationdata> &stations,
	vector<tempdata> &data,
	vector<long long int> &country_codes,
	float min_temp, float max_temp,
	int start_month, int end_month)
{
	string current_name="";
	long long int current_number=0;
	float current_latitude=0,current_longitude=0;
	// Get a list of wmo stations which exist within the data
	vector<long long int> stations_list;
	get_stations_from_data(data,
						   stations_list,
						   min_temp, max_temp,
						   start_month, end_month,
						   country_codes);

	string str = "";
	ifstream iFile(filename.c_str());
	while (!iFile.eof()) {
		getline(iFile, str);

		if (str != "") {
			const char* str2 = str.c_str();
			string str3 = "";
			string station_number_str = "";
			int field = 0;
			int ctr = 0;
			string degrees = "";
			string mins = "";
			string secs = "";
			bool north = true;
			bool west = true;
			for (int i = 0; i < (int)str.size(); i++) {
				if (str2[i] != ';') {
					str3 += str2[i];
					if (str2[i] == '-') {
						ctr++;
					}
					else {
						if (str2[i] == 'N') {
							north = true;
						}
						else {
							if (str2[i] == 'S') {
								north = false;
							}
							else {
								if (str2[i] == 'E') {
									west = false;
								}
								else {
									if (str2[i] == 'W') {
										west = true;
									}
									else {
										switch(ctr) {
										case 0: {
											degrees += str2[i];
											break;
										}
										case 1: {
											mins += str2[i];
											break;
										}
										case 2: {
											secs += str2[i];
											break;
										}
										}
									}
								}
							}
						}
					}
				}
				else {
					switch(field) {
					case 0: { station_number_str += str3; break; }
					case 1: {
						station_number_str += str3;
						if ((stations_list.size()==0) ||
							(station_number_in_data(
													atoi(station_number_str.c_str()),
													stations_list))) {
							current_number = (long long int)atof(station_number_str.c_str());
						}
						else {
							i = (int)str.size();
						}
						break;
					}
					case 3: {
						current_name = str3;
						break;
					}
					case 7: { // latitude N
						float lat = atof(degrees.c_str()) + (atof(mins.c_str())/60.0f);
						if (!north) lat = -lat;
						current_latitude = lat;
						break;
					}
					case 8: { // longitude W
						float lng = atof(degrees.c_str()) + (atof(mins.c_str())/60.0f);
						if (!west) lng = -lng;
						current_longitude = lng;
						break;
					}
					case 11: { // altitude (metres)
						float current_altitude = atof(str3.c_str());
						stationdata s;
						s.name = current_name;
						s.number = current_number;
						s.latitude = current_latitude;
						s.longitude = current_longitude;
						s.altitude = current_altitude;
						s.topography_class="";
						stations.push_back(s);
						break;
					}
					}
					field++;
					str3 = "";
					ctr = 0;
					degrees = "";
					mins = "";
					secs = "";
				}
			}
		}
	}
	iFile.close();
}

void ghcn::load_stations(
    string filename,
	float ghcn_version,
	vector<stationdata> &stations,
	vector<tempdata> &data,
	vector<long long int> &country_codes,
	float min_temp, float max_temp,
	int start_month, int end_month,
	string population_class)
{
	if (FileExists(filename)) {
		if ((ghcn_version>=2.0f) && (ghcn_version<3.0f)) {
			load_stations_v2(filename,
							 stations,
							 data,
							 country_codes,
							 min_temp, max_temp,
							 start_month, end_month);
		}
		if (ghcn_version>=3.0f) {
			load_stations_v3(filename,
							 stations,
							 data,
							 country_codes,
							 min_temp, max_temp,
							 start_month, end_month,
							 population_class);
		}
	}
}

void ghcn::load_v2(
	string filename,
	int start_year,
	int end_year,
	vector<long long int> &country_codes,
	vector<long long int> &station_numbers,
	vector<tempdata> &data,
	int entity_type)
{

	ifstream iFile(filename.c_str());

	string str;
	data.clear();
	while (!iFile.eof()) {
		getline(iFile, str);

		if (str != "") {
			int country_code = atoi(str.substr(0,3).c_str());
			long long int station = (long long int)atoi(str.substr(3,5).c_str());
			if (((entity_type == 0) && (((int)country_codes.size() == 0) ||
										(vector_contains(country_codes, country_code)))) ||
				((entity_type == 1) && (vector_contains(station_numbers, station)))) {

				int modifier = atoi(str.substr(8,3).c_str());
				int year = atoi(str.substr(12,4).c_str());
				if ((year >= start_year) && (year <= end_year)) {
					for (int m = 0; m < 12; m++) {
						int offset = 16 + (m*5);
						if ((int)str.size() > offset+5) {
							int tempint = atoi(str.substr(offset, 5).c_str());
							if (tempint != -9999) {
								float temp = tempint / 10.0f;

								tempdata data_point;
								data_point.country_code = country_code;
								data_point.station = station;
								data_point.modifier = modifier;
								data_point.year = year;
								data_point.month = m;
								data_point.temperature = temp;

								data.push_back(data_point);
							}
						}
					}
				}
			}
		}
	}

	iFile.close();
}

void ghcn::load_v3(
	string filename,
	int start_year,
	int end_year,
	vector<long long int> &country_codes,
	vector<long long int> &station_numbers,
	vector<tempdata> &data,
	int entity_type)
{

	ifstream iFile(filename.c_str());

	string str;
	data.clear();
	while (!iFile.eof()) {
		getline(iFile, str);

		if (str != "") {
			int country_code = atoi(str.substr(0,3).c_str());
			long long int station = (long long int)atof(str.substr(0,11).c_str());

			if (((entity_type == 0) && (((int)country_codes.size() == 0) ||
										(vector_contains(country_codes, (long long int)country_code)))) ||
				((entity_type == 1) && (vector_contains(station_numbers, station)))) {

				int year = atoi(str.substr(11,4).c_str());

				if ((year >= start_year) && (year <= end_year)) {

					// AVG = monthly mean
					string element = str.substr(16,3).c_str();
									
					for (int m = 0; m < 12; m++) {
						int offset = 19 + (m*8);
						if ((int)str.size() > offset+8) {
							int tempint = atoi(str.substr(offset, 5).c_str());
							if (tempint != -9999) {
								string data_measurement_flag = str.substr(offset+5,1);
								string quality_control_flag = str.substr(offset+6,1);
								string data_source_flag = str.substr(offset+7,1);

								float temp = tempint / 100.0f;

								tempdata data_point;
								data_point.country_code = country_code;
								data_point.station = station;
								data_point.modifier = 0;
								if (element=="MIN") {
								    data_point.modifier = 1;
								}
								else {
									if (element=="MAX") {
										data_point.modifier = 2;
									}
								}
								data_point.year = year;
								data_point.month = m;
								data_point.temperature = temp;
								data_point.flag_data_measurement = 0;
								data_point.flag_quality_control = 0;
								data_point.flag_data_source = 0;
								data_point.flag_data_measurement = (data_measurement_flag.c_str())[0];
								data_point.flag_quality_control = (quality_control_flag.c_str())[0];
								data_point.flag_data_source = (data_source_flag.c_str())[0];
								data.push_back(data_point);
							}
						}
					}
				}
			}
		}
	}

	iFile.close();
}

void ghcn::load(
	string filename,
	float version,
	int start_year,
	int end_year,
	vector<long long int> &country_codes,
	vector<long long int> &station_numbers,
	vector<tempdata> &data,
	int entity_type)
{
	if (FileExists(filename)) {

		if ((version >= 2.0f) && (version < 3.0f)) {
			load_v2(filename,start_year,end_year,
					country_codes,station_numbers,data,entity_type);
		}

		if (version >= 3.0f) {
			load_v3(filename,start_year,end_year,
					country_codes,station_numbers,data,entity_type);
		}

	}
	else {
		printf("File not found\n%s\n", filename.c_str());
	}

}
